package function;

import java.io.File;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Edge {
	private String code;//边（路）的编号
	private String scenic1;
	private String scenic2;
	private String distance;

	public Edge() {
		this.code = null;
		this.scenic1 = null;
		this.scenic2 = null;
		this.distance = null;
	}

	public Edge(String code, String scenic1, String scenic2, String distance) {
		this.code = code;
		this.scenic1 = scenic1;
		this.scenic2 = scenic2;
		this.distance = distance;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getScenic1() {
		return scenic1;
	}

	public void setScenic1(String scenic1) {
		this.scenic1 = scenic1;
	}

	public String getScenic2() {
		return scenic2;
	}

	public void setScenic2(String scenic2) {
		this.scenic2 = scenic2;
	}

	public String getDistance() {
		return distance;
	}

	public void setDistance(String distance) {
		this.distance = distance;
	}
    //通过ArrayList打印出所有边的信息
	public ArrayList<String> display() {
		ArrayList<String> g = getAllEdges();
		return g;
	}
	//管理员添加边
	public boolean add() {
		boolean a = addEdge(this);
		return a;
	}
	//管理员删除边
	public boolean delete(String text) {
		boolean d = deleteEdge(text);
		return d;
	}
	//管理员修改边的信息
	public boolean modify(String text) {
		boolean m = modifyEdge(text, this);
		return m;
	}
	/*通过传入的text（text中有该边的code和scenic1和scenic2）返回对应的边对象，
	text对应gui界面显示的内容
	通过看界面上按钮组后显示的内容即可理解此方法的作用
	*/
	public Edge find(String text) {
		Edge n = findEdge(this, text);
		return n;
	}
	/*查询景点，text对应gui界面用户选中的JRadioButton的text内容
	 * 根据用户选择的JRadioButton打印出此边的信息 
	 */
	public String inquire(String text) {
		String i = inquireEdge(text);
		return i;
	}
	//保存道路信息的xml文件路径
	static String xmlPath = "edge.xml";
	/*getAllEdges()方法从xml文件中获取所有景点的code和scenic1及scenic2并放入list中，返回list
	 * 用于在界面中显示
	 */
	private ArrayList<String> getAllEdges() {
		ArrayList<String> list = new ArrayList<String>();
		/*
		 * 创建文件工厂实例，用于解析xml文件
		 */
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		// 如果创建的解析器在解析XML文档时必须删除元素内容中的空格，则为true，否则为false
		dbf.setIgnoringElementContentWhitespace(true);

		try {
			/*
			 * 创建文件对象
			 */
			DocumentBuilder db = dbf.newDocumentBuilder();// 创建解析器，解析XML文档
			Document doc = db.parse(xmlPath); // 使用dom解析xml文件
			/*
			 * 遍历列表，进行XML文件的数据提取
			 */
			// 根据节点名称来获取所有相关的节点
			NodeList sonlist = doc.getElementsByTagName("edge");
			for (int i = 0; i < sonlist.getLength(); i++) // 循环处理对象
			{
				// 节点属性的处理
				Element son = (Element) sonlist.item(i);
				NodeList elements1 = son.getElementsByTagName("code");
				NodeList elements2 = son.getElementsByTagName("scenic1");
				NodeList elements3 = son.getElementsByTagName("scenic2");
				Node node1 = elements1.item(0);
				Node node2 = elements2.item(0);
				Node node3 = elements3.item(0);

				if (node1.getNodeType() == Node.ELEMENT_NODE && node2.getNodeType() == Node.ELEMENT_NODE && node3.getNodeType() == Node.ELEMENT_NODE) {
					String value1 = node1.getFirstChild().getNodeValue();
					String value2 = node2.getFirstChild().getNodeValue();
					String value3 = node3.getFirstChild().getNodeValue();
					//value1为边的code  value2为边的scenic1  value3为边的scenic2
					list.add(value1 + "  " + value2 + "  " + value3);
				}
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return list;
	}
	/*添加一条边，添加成功则返回true，添加失败返回false
	 * 和Scenic类的addScenic方法一样，详细解释可参见Scenic类的addScenic方法
	 */
	private boolean addEdge(Edge edge) {
		// 创建文件工厂实例，用于解析xml文件
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setIgnoringElementContentWhitespace(false);

		try {
			//获取DOM解析器
			DocumentBuilder db = dbf.newDocumentBuilder();
			//用DOM解析器解析xml并生成DOM树
			Document xmldoc = db.parse(xmlPath);

			// 根据节点名称来获取所有相关的节点
			NodeList sonlist = xmldoc.getElementsByTagName("edge");
			for (int i = 0; i < sonlist.getLength(); i++) // 循环处理对象
				{
				// 节点属性的处理
				Element son = (Element) sonlist.item(i);
				NodeList elements;
				elements = son.getElementsByTagName("code");
				Node node0 = elements.item(0);

				if (node0.getNodeType() == Node.ELEMENT_NODE) {
					//value0为边的编号code
					String value0 = node0.getFirstChild().getNodeValue();
					//新添加的边的code不能和已有边的code相等
					if (value0.equals(edge.getCode())) {
						return false;
						}
					}
				}

			// 获取根节点（xml的树型结构）
			Element root = xmldoc.getDocumentElement();
			// 创建节点son，用于构建出新添加的边
			Element son = xmldoc.createElement("edge");

			Element code = xmldoc.createElement("code");
			code.setTextContent(edge.getCode());
			son.appendChild(code);

			Element scenic1 = xmldoc.createElement("scenic1");
			scenic1.setTextContent(edge.getScenic1());
			son.appendChild(scenic1);

			Element scenic2 = xmldoc.createElement("scenic2");
			scenic2.setTextContent(edge.getScenic2());
			son.appendChild(scenic2);

			Element distance = xmldoc.createElement("distance");
			distance.setTextContent(edge.getDistance());
			son.appendChild(distance);

			// 把son添加到根节点中
			root.appendChild(son);

			// 保存到xml文件
			TransformerFactory factory = TransformerFactory.newInstance();
			Transformer former = factory.newTransformer();
			former.setOutputProperty(OutputKeys.VERSION, "1.0");
			former.setOutputProperty(OutputKeys.INDENT, "yes");// 缩进
			former.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			former.transform(new DOMSource(xmldoc), new StreamResult(new File(xmlPath)));

		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return true;
	}
	//删除边，和Scenic类的deleteScenic方法一样，详情参见Scenic类的deleteScenic方法
	private boolean deleteEdge(String text) {
		String c[] = text.split("  ");
		String code = c[0];

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setIgnoringElementContentWhitespace(true);

		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document xmldoc = db.parse(xmlPath);
			// 获取根节点
			Element root = xmldoc.getDocumentElement();
			Element son = (Element) selectSingleNode("/edgeList/edge/code[text()='" + code + "']/parent::*", root);

			// 删除该节点
			root.removeChild(son);
			// 保存到xml文件 
			TransformerFactory factory = TransformerFactory.newInstance();
			Transformer former = factory.newTransformer();
			former.setOutputProperty(OutputKeys.VERSION, "1.0");
			former.setOutputProperty(OutputKeys.INDENT, "yes");// 缩进
			former.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			former.transform(new DOMSource(xmldoc), new StreamResult(new File(xmlPath)));
			return true;
		} catch (Exception e) {
			System.out.println(e.getMessage());
			return false;
		}
	}
	//查询边，和Scenic类的inquireScenic方法一样，详情参见Scenic类的inquireScenic方法
	private static String inquireEdge(String text) {
		String c[] = text.split(" ");
		String code = c[0];

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		// 如果创建的解析器在解析XML文档时必须删除元素内容中的空格，则为true，否则为false
		dbf.setIgnoringElementContentWhitespace(true);

		String information = "<html><body>";
		try {

			DocumentBuilder db = dbf.newDocumentBuilder();// 创建解析器，解析XML文档
			Document doc = db.parse(xmlPath); // 使用dom解析xml文件

			// 根据节点名称来获取所有相关的节点
			NodeList sonlist = doc.getElementsByTagName("edge");
			for (int i = 0; i < sonlist.getLength(); i++) // 循环处理对象
			{
				// 节点属性的处理
				Element son = (Element) sonlist.item(i);
				NodeList elements;
				elements = son.getElementsByTagName("code");
				Node node0 = elements.item(0);

				if (node0.getNodeType() == Node.ELEMENT_NODE) {
					String value0 = node0.getFirstChild().getNodeValue();
					if (value0.equals(code)) {
						for (Node node = son.getFirstChild(); node != null; node = node.getNextSibling()) {
							// 判断是否为元素节点
							if (node.getNodeType() == Node.ELEMENT_NODE) {
								String name = node.getNodeName();
								String value = node.getFirstChild().getNodeValue();
								information += (name + ":" + value + "<br/>");
							}
						}
					}
				}
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		information += "</body></html>";
		return information;
	}
	/*在ManagerEdge中实现管理员修改路信息的修改按钮处调用了此方法
	 * 通过结合界面上按钮组后显示的内容即可理解此方法中text的含义
	 * 通过传入用户选择的路（JRadioButton）打印出此路的信息，然后用户再对路信息进行修改
	*/
	private Edge findEdge(Edge edge, String text) {
		String c[] = text.split("  ");
		String code = c[0];

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setIgnoringElementContentWhitespace(true);

		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document xmldoc = db.parse(xmlPath);
			// 获取根节点（xml的树型结构）
			Element root = xmldoc.getDocumentElement();
			//构建str用于查询满足特定条件的结点
			String str = "/edgeList/edge/code[text()='" + code + "']/parent::*";
			//将str作为参数传入selectSingleNode方法查找满足条件的结点
			Element son = (Element) selectSingleNode(str, root);

			for (Node node = son.getFirstChild(); node != null; node = node.getNextSibling()) {
				// 判断是否为元素节点
				if (node.getNodeType() == Node.ELEMENT_NODE) {
					String name0 = node.getNodeName();
					String value = node.getFirstChild().getNodeValue();
					if ("code".equals(name0)) {
						edge.setCode(value);
					} else if ("scenic1".equals(name0)) {
						edge.setScenic1(value);
					} else if ("scenic2".equals(name0)) {
						edge.setScenic2(value);
					} else {
						edge.setDistance(value);
					}
				}
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return edge;
	}
	//管理员修改路信息
	private boolean modifyEdge(String text, Edge edge) {
		String c[] = text.split("  ");
		String code = c[0];

		// 创建文件工厂实例，用于解析xml文件
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setIgnoringElementContentWhitespace(true);

		try {
			// 从XML文档中获取DOM文档实例
			DocumentBuilder db = dbf.newDocumentBuilder();
			// 获取Document对象
			Document xmldoc = db.parse(xmlPath);

			// 获取根节点
			Element root = xmldoc.getDocumentElement();
			//构建str用于查询满足特定条件的结点
			String str = "/edgeList/edge/code[text()='" + code + "']/parent::*";
			//将str作为参数传入selectSingleNode方法查找满足条件的结点
			Element per = (Element) selectSingleNode(str, root);

			per.getElementsByTagName("code").item(0).setTextContent(edge.getCode());
			per.getElementsByTagName("scenic1").item(0).setTextContent(edge.getScenic1());
			per.getElementsByTagName("scenic2").item(0).setTextContent(edge.getScenic2());
			per.getElementsByTagName("distance").item(0).setTextContent(edge.getDistance());
			// 保存到xml文件
			TransformerFactory factory = TransformerFactory.newInstance();
			Transformer former = factory.newTransformer();
			former.setOutputProperty(OutputKeys.VERSION, "1.0");
			former.setOutputProperty(OutputKeys.INDENT, "yes");// 缩进
			former.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			former.transform(new DOMSource(xmldoc), new StreamResult(new File(xmlPath)));
			return true;
		} catch (Exception e) {
			System.out.println(e.getMessage());
			return false;
		}
	}
	/*
	 * 由于文本文件均采用xml格式，selectSingleNode方法在对四个xml文件进行操作的类
	 * Manager类，Notice类，Edge类，Scenic类中均有
	 * 此方法用于查询结点（xml为树型结构），且此方法只返回单个结点
	 */
	private static Node selectSingleNode(String express, Element source) {
		// 创建XPath工厂
		XPathFactory xpathFactory = XPathFactory.newInstance();
		// 创建XPath对象
		XPath xpath = xpathFactory.newXPath();

		Node result = null;
		try {
			//计算XPath表达式
			result = (Node) xpath.evaluate(express, source, XPathConstants.NODE);
		} catch (XPathExpressionException e) {
			System.out.println(e.getMessage());
		}
		//返回目标结点
		return result;
	}
	//取得边的个数
	public int getTotalNumber() {
		int i = 0;
		// 创建文件工厂实例，用于解析xml文件
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		// 如果创建的解析器在解析XML文档时必须删除元素内容中的空格，则为true，否则为false
		dbf.setIgnoringElementContentWhitespace(true);
		try {
			// 创建文件对象
			DocumentBuilder db = dbf.newDocumentBuilder();// 创建解析器，解析XML文档
			Document doc = db.parse(xmlPath); // 使用dom解析xml文件
			// 遍历列表，进行XML文件的数据提取
			// 根据节点名称来获取所有相关的节点
			NodeList sonlist = doc.getElementsByTagName("edge");
			i = sonlist.getLength();

		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return i;
	}
}